/**
 * \file stream.c
 **/

#include "stream.h"

/* Get a void* to the chunk data. */
#define rs_stream_chunk_data(s) ((void*) ((s)->stream_chunk.chunk + 1))

/* Get the size of the chunk data (not including the chunk header */
#define rs_stream_chunk_size(s) ((s)->stream_chunk.chunk->size \
                                 - sizeof(Chunk))

bool rs_stream_end(RipeStream* stream)
{
  switch (stream->type) {
    case RS_STREAM_FILE:
      return feof(stream->stream_file.file);
    case RS_STREAM_CHUNK:
      uint32_t chunk_size = rs_stream_chunk_size(stream);
      assert(stream->cursor < chunk_size);
      if (stream->cursor == chunk_size) return true;
      else return false;
    default:
      assert_never();
  }
}

uint32_t rs_stream_read(RipeStream* stream, uint32_t n, void* buffer)
{
  switch (stream->type) {
    case RS_STREAM_FILE:
      return fread(buffer, 1, n, stream->stream_file.file);
    case RS_STREAM_CHUNK:
      uint32_t size = rs_stream_chunk_size(stream);
      void* chunk_data = rs_stream_chunk_data(stream);
      uint32_t to_read = (n > (size - stream->cursor)) ? (size - stream->cursor) : n;
      memcpy(buffer, chunk_data + stream->cursor, to_read);
      stream->cursor += to_read;
      return to_read;
    default:
      assert_never();
  }
}

int rs_stream_seek(RipeStream* stream, RipeStreamStart start, int32_t n);

uint32_t rs_stream_tell(RipeStream* stream);

uint32_t rs_stream_write(RipeStream* stream, uint32_t n, void* buffer);
